package cn.harry.modular.oss.service.impl;

import cn.harry.common.exception.ApiException;
import cn.harry.modular.oss.config.OssConfig;
import cn.harry.modular.oss.vo.OssCallbackResult;
import cn.harry.modular.oss.vo.OssPolicyResult;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.util.DateUtils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import cn.harry.modular.oss.service.OssService;
import cn.harry.modular.oss.vo.OssCallbackParam;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * ClassName: OssServiceImpl Description: oss上传管理Service实现类
 *
 * @author honghh Date 2019/10/14 11:50 Copyright (C) www.tech-harry.cn
 */
@Slf4j
@Service
public class OssServiceImpl implements OssService {

	@Resource
	private OssConfig ossConfig;

	@Resource
	private OSS ossClient;

	/**
	 * 签名生成
	 */
	@Override
	public OssPolicyResult policy() {
		OssPolicyResult result = new OssPolicyResult();
		// 存储目录
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String dir = ossConfig.getDirPrefix() + sdf.format(new Date());
		// 签名有效期
		long expireEndTime = System.currentTimeMillis()
				+ Long.parseLong(ossConfig.getPolicyExpire()) * 1000;
		Date expiration = new Date(expireEndTime);
		// 文件大小
		long maxSize = Long.parseLong(ossConfig.getMaxSize()) * 1024 * 1024;
		// 回调
		OssCallbackParam callback = new OssCallbackParam();
		callback.setCallbackUrl(ossConfig.getCallback());
		callback.setCallbackBody(
				"filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
		callback.setCallbackBodyType("application/x-www-form-urlencoded");
		// 提交节点
		String action = "http://" + ossConfig.getBucketName() + "."
				+ ossConfig.getEndpoint();
		try {
			PolicyConditions policyConditions = new PolicyConditions();
			policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,
					0, maxSize);
			policyConditions.addConditionItem(MatchMode.StartWith,
					PolicyConditions.COND_KEY, dir);
			String postPolicy = ossClient.generatePostPolicy(expiration,
					policyConditions);
			byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
			String policy = BinaryUtil.toBase64String(binaryData);
			String signature = ossClient.calculatePostSignature(postPolicy);
			String callbackData = BinaryUtil.toBase64String(
					JSONUtil.parse(callback).toString().getBytes(StandardCharsets.UTF_8));
			// 返回结果]
			result.setAccessKeyId(ossConfig.getAccessKeyId());
			result.setPolicy(policy);
			result.setSignature(signature);
			result.setDir(dir);
			result.setCallback(callbackData);
			result.setHost(action);
		}
		catch (Exception e) {
			log.error("签名生成失败", e);
		}
		return result;
	}

	@Override
	public OssCallbackResult callback(HttpServletRequest request) {
		OssCallbackResult result = new OssCallbackResult();
		String filename = request.getParameter("filename");
		filename = "http://".concat(ossConfig.getBucketName()).concat(".")
				.concat(ossConfig.getEndpoint()).concat("/").concat(filename);
		result.setFilename(filename);
		result.setSize(request.getParameter("size"));
		result.setMimeType(request.getParameter("mimeType"));
		result.setWidth(request.getParameter("width"));
		result.setHeight(request.getParameter("height"));
		return result;
	}

	@Override
	public String upload(byte[] data, String path) {
		return upload(new ByteArrayInputStream(data), path);
	}

	@Override
	public String upload(InputStream inputStream, String path) {
		try {
			ossClient.putObject(ossConfig.getBucketName(), path, inputStream);
		}
		catch (Exception e) {
			throw new ApiException("上传文件失败，请检查配置信息", e);
		}
		return ossConfig.getDomain() + "/" + path;
	}

	@Override
	public String uploadSuffix(byte[] data, String suffix) {
		return upload(data, getPath(ossConfig.getDirPrefix(), suffix));
	}

	@Override
	public String uploadSuffix(InputStream inputStream, String suffix) {
		return upload(inputStream, getPath(ossConfig.getDirPrefix(), suffix));
	}

	/**
	 * 文件路径
	 */
	private String getPath(String prefix, String suffix) {
		// 生成uuid
		String uuid = IdUtil.fastSimpleUUID();
		// 文件路径
		String path = DateUtils.format(DateUtil.date(), "yyyyMMdd") + "/" + uuid;

		if (StrUtil.isNotBlank(prefix)) {
			path = prefix + path;
		}
		return path + suffix;
	}

}
